Skip to content

Migrate to AGP 9.2.1 + Gradle 9.4.1 (new DSL, built-in Kotlin)#61

Merged
hawkff merged 3 commits into
mainfrom
chore/agp9-migration
Jun 23, 2026
Merged

Migrate to AGP 9.2.1 + Gradle 9.4.1 (new DSL, built-in Kotlin)#61
hawkff merged 3 commits into
mainfrom
chore/agp9-migration

Conversation

@hawkff

@hawkff hawkff commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Summary

Migrates the build toolchain to the latest Android Gradle Plugin 9.x line, adopting AGP 9's new DSL and built-in Kotlin (no opt-out flags). Verified on Android with a local debug build.

Changes

  • AGP 8.13.2 -> 9.2.1 (buildSrc/build.gradle.kts). AGP 9.2.1 bundles KGP 2.3.10, matching the version already pinned.
  • Gradle 8.14.5 -> 9.4.1 (gradle/wrapper/gradle-wrapper.properties, pinned distributionSha256Sum).
  • Built-in Kotlin: dropped the kotlin-android plugin from app/build.gradle.kts. AGP 9 enables built-in Kotlin by default, so applying the plugin would clash.
  • New DSL in Helpers.kt: removed the legacy variant API (AbstractAppExtension / applicationVariants / BaseVariantOutputImpl) that powered in-place APK output renaming - it no longer exists under android.newDsl=true.
  • RenameApkTask (new): replaces APK renaming via androidComponents.onVariants + artifacts.use(...).toListenTo(SingleArtifact.APK). It copies each ABI split into build/outputs/renamed_apks/<variant>/ as NekoBox-<version>[-<abi>].apk and preserves output-metadata.json. Public APIs only (no AGP internals, no Gradle impldep).
  • CI workflows: point the arm64-v8a APK find/upload at renamed_apks, with a guard that fails the job if no APK is found.
  • Minor Gradle 9 deprecation fixes (tasks.register, jniLibs.directories, rootProject.layout.buildDirectory).

KSP stays at 2.3.9 (latest; the 2.3 line dropped the -kspRev suffix and is compatible with KGP 2.3.10).

Testing

  • ./gradlew app:assembleOssDebug builds successfully on JDK 17 (matches CI).
  • Confirmed renameApksForOssDebug runs automatically during assemble (clean rebuild after deleting outputs) and produces NekoBox-1.4.2-mod-12-arm64-v8a.apk etc. + output-metadata.json.
  • aapt2 dump badging on the arm64 APK: package=com.nb4a.debug, versionName=1.4.2-mod-12, native-code=arm64-v8a.
  • Device install/runtime smoke test pending (verified on Android).

Greptile Summary

This PR migrates the Android build toolchain from AGP 8.13.2/Gradle 8.14.5 to AGP 9.2.1/Gradle 9.4.1, adopting AGP 9's new DSL and built-in Kotlin while replacing the removed applicationVariants/BaseVariantOutputImpl APK-renaming API with a new RenameApkTask that uses the public androidComponents.onVariants + artifacts.use(...).toListenTo(SingleArtifact.APK) pipeline.

  • Toolchain upgrades: AGP bumped to 9.2.1 (bundles KGP 2.3.10), Gradle to 9.4.1 with pinned SHA, kotlin-android plugin dropped since AGP 9 enables built-in Kotlin by default to avoid an "extension already registered" clash.
  • RenameApkTask (new): Copies each ABI-split APK from outputs/apk/<variant>/ into outputs/renamed_apks/<variant>/ as NekoBox-<version>[-<abi>].apk; intentionally omits builtArtifacts.save() to avoid emitting a misleading output-metadata.json with stale original paths (previously flagged and now explicitly documented in the code).
  • CI workflows: All four workflow files updated to point find/upload at renamed_apks, with a fail-fast guard if no arm64-v8a APK is present; $APK in dirname is now properly double-quoted.

Confidence Score: 5/5

Clean build toolchain migration with no correctness issues found; safe to merge.

All three issues flagged in earlier review rounds (misleading output-metadata.json, unquoted shell variable, missing trailing newline) are explicitly addressed in this revision. The new RenameApkTask uses only public AGP APIs, correctly annotates inputs/outputs for Gradle's incremental build, and the CI guard ensures a missing APK fails fast rather than silently uploading nothing. No new defects were identified across any of the changed files.

No files require special attention.

Important Files Changed

Filename Overview
buildSrc/src/main/kotlin/RenameApkTask.kt New task implementing APK renaming via public AGP artifact APIs; correctly uses @InputDirectory, @OutputDirectory, @internal for BuiltArtifactsLoader, and omits misleading output-metadata.json.
buildSrc/src/main/kotlin/Helpers.kt Removed AbstractAppExtension/BaseVariantOutputImpl usage; build type config now applies directly on ApplicationExtension; APK renaming wired via androidComponents.onVariants in setupApp().
buildSrc/build.gradle.kts AGP dependency bumped from 8.13.2 to 9.2.1; KGP 2.3.10 kept explicit for clarity.
gradle/wrapper/gradle-wrapper.properties Gradle wrapper updated from 8.14.5 to 9.4.1 with new pinned distributionSha256Sum.
app/build.gradle.kts Dropped kotlin-android plugin with explanatory comment; kotlin-parcelize remains, which is correct as it's a compiler plugin independent of the KGP application plugin.
build.gradle.kts Gradle 9 deprecation fix: rootProject.buildDir replaced with rootProject.layout.buildDirectory in the clean task.
.github/workflows/build.yml Updated find path to renamed_apks with head -n 1, added fail-fast guard, quoted $APK in dirname.
.github/workflows/ci.yml Same APK find/guard/quote fix as build.yml; targets assembleOssDebug.
.github/workflows/preview.yml Same APK find/guard/quote fix; targets assemblePreviewRelease and will resolve APKs under renamed_apks/previewRelease.
.github/workflows/release.yml Same APK find/guard/quote fix as build.yml; targets assembleOssRelease for release publication.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["`./gradlew assembleOssRelease`"] --> B[AGP compiles & links APKs]
    B --> C["`outputs/apk/ossRelease/
    app-oss-arm64-v8a-release.apk
    app-oss-armeabi-v7a-release.apk
    app-oss-x86_64-release.apk
    app-oss-x86-release.apk`"]
    C -->|toListenTo SingleArtifact.APK| D["`renameApksForOssRelease
    (RenameApkTask)`"]
    D -->|BuiltArtifactsLoader enumerates splits| E{ABI detected in filename?}
    E -->|yes| F["`NekoBox-VERSION-arm64-v8a.apk
    NekoBox-VERSION-armeabi-v7a.apk
    NekoBox-VERSION-x86_64.apk
    NekoBox-VERSION-x86.apk`"]
    E -->|no — universal APK| G["`NekoBox-VERSION.apk`"]
    F --> H["`outputs/renamed_apks/ossRelease/`"]
    G --> H
    H --> I["`CI: find *arm64-v8a*.apk | head -n 1`"]
    I -->|APK found| J[Upload artifact directory]
    I -->|not found| K[exit 1 — fail job]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["`./gradlew assembleOssRelease`"] --> B[AGP compiles & links APKs]
    B --> C["`outputs/apk/ossRelease/
    app-oss-arm64-v8a-release.apk
    app-oss-armeabi-v7a-release.apk
    app-oss-x86_64-release.apk
    app-oss-x86-release.apk`"]
    C -->|toListenTo SingleArtifact.APK| D["`renameApksForOssRelease
    (RenameApkTask)`"]
    D -->|BuiltArtifactsLoader enumerates splits| E{ABI detected in filename?}
    E -->|yes| F["`NekoBox-VERSION-arm64-v8a.apk
    NekoBox-VERSION-armeabi-v7a.apk
    NekoBox-VERSION-x86_64.apk
    NekoBox-VERSION-x86.apk`"]
    E -->|no — universal APK| G["`NekoBox-VERSION.apk`"]
    F --> H["`outputs/renamed_apks/ossRelease/`"]
    G --> H
    H --> I["`CI: find *arm64-v8a*.apk | head -n 1`"]
    I -->|APK found| J[Upload artifact directory]
    I -->|not found| K[exit 1 — fail job]
Loading

Reviews (2): Last reviewed commit: "Address review bots: metadata, shell quo..." | Re-trigger Greptile

hawkff added 2 commits June 22, 2026 21:20
- buildSrc: Android Gradle Plugin 8.13.2 -> 9.2.1 (bundles KGP 2.3.10,
  matching the pinned Kotlin version). Gradle wrapper 8.14.5 -> 9.4.1.
- app: drop the kotlin-android plugin; AGP 9 provides built-in Kotlin
  (android.builtInKotlin defaults to true), so applying it would clash.
- Helpers.kt: adopt AGP 9's new DSL. Remove the legacy variant API
  (AbstractAppExtension / applicationVariants / BaseVariantOutputImpl)
  used for in-place APK output renaming, which no longer exists under
  android.newDsl=true.
- Replace APK renaming with RenameApkTask, wired via
  androidComponents.onVariants + artifacts.use(...).toListenTo(APK).
  It copies each ABI split into build/outputs/renamed_apks/<variant>/
  as NekoBox-<version>[-<abi>].apk and preserves output-metadata.json.
  Public APIs only (no AGP internals, no Gradle impldep).
- CI workflows: point the arm64-v8a APK find/upload at renamed_apks.
- Fix minor Gradle 9 deprecations (tasks.register, jniLibs.directories,
  rootProject.layout.buildDirectory).

KSP stays at 2.3.9 (latest; the 2.3 line dropped the -kspRev suffix and
is compatible with KGP 2.3.10). Verified locally: app:assembleOssDebug
builds and renameApksForOssDebug runs as part of assemble.
- RenameApkTask.baseName: @internal -> @input so a version bump correctly
  invalidates the task and re-copies APKs with the new name (avoids stale
  output). Verified renameApksForOssDebug still runs automatically during a
  clean app:assembleOssDebug (it listens on SingleArtifact.APK).
- CI workflows: fail loudly if no arm64-v8a APK is found under
  renamed_apks instead of silently proceeding with an empty path.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR upgrades the Android Gradle Plugin from 8.x to 9.2.1 and the Gradle wrapper from 8.14.5 to 9.4.1. It introduces a new RenameApkTask that copies APK artifacts to build/outputs/renamed_apks/<variant>/ with friendly filenames. Helpers.kt is migrated from legacy AGP variant/output APIs to the androidComponents.onVariants DSL to wire this task. All four CI workflows are updated to discover APKs from the new output path with added validation.

Changes

AGP 9 Upgrade and APK Renaming Pipeline

Layer / File(s) Summary
Gradle and AGP version bump
gradle/wrapper/gradle-wrapper.properties, buildSrc/build.gradle.kts, app/build.gradle.kts, build.gradle.kts
Gradle wrapper updated to 9.4.1 with new checksum; AGP bumped to 9.2.1 in buildSrc with rationale comments; kotlin-android plugin removed from app module (AGP 9 provides built-in support); root clean task updated to use layout.buildDirectory.
New RenameApkTask
buildSrc/src/main/kotlin/RenameApkTask.kt
New DefaultTask with abstract input/output/builtArtifactsLoader/baseName properties; taskAction wipes the output dir, loads APK artifacts, derives ABI suffix from an ordered ABIS list, copies each APK as NekoBox-<versionName>[-<abi>].apk, and saves output-metadata.json.
Helpers.kt AGP 9+ DSL migration
buildSrc/src/main/kotlin/Helpers.kt
Removes AbstractAppExtension casts and BaseVariantOutputImpl renaming; adds androidComponents extension property; migrates buildTypes to AGP 9 DSL flags; replaces applicationVariants iteration with androidComponents.onVariants registering RenameApkTask per variant wired to SingleArtifact.APK and outputting to renamed_apks/<variant>.
CI/CD workflows: new APK output path
.github/workflows/build.yml, .github/workflows/ci.yml, .github/workflows/preview.yml, .github/workflows/release.yml
All four workflows switch APK discovery from app/build/outputs/apk to app/build/outputs/renamed_apks; each now emits an error to stderr and exits with code 1 when no arm64-v8a APK is found.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • hawkff/NekoBoxForAndroid#7: Directly involves Gradle wrapper and AGP dependency version bumps in the same buildSrc/build.gradle.kts and gradle/wrapper/gradle-wrapper.properties files.

Poem

🐰 Hoppin' through the build files with glee,
Old AGP eight is history!
A RenameApkTask hops into place,
Copying APKs with elegant grace.
renamed_apks is where they land now,
The CI workflows all take a bow! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: migration to AGP 9.2.1 and Gradle 9.4.1 with new DSL and built-in Kotlin support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is directly related to the changeset, detailing the AGP 9.2.1 migration, Gradle 9.4.1 upgrade, new RenameApkTask implementation, and CI workflow updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Around line 138-143: The find command on line 138 can return multiple APK
matches, and the unquoted dirname variable reference on line 143 will emit
multiple paths into GITHUB_ENV, corrupting the artifact path. Modify the APK
variable assignment to pipe the find result through head -1 to select only the
first match, ensuring a single APK path is captured. Then quote the variable in
the dirname call by changing dirname $APK to dirname "$APK" to properly handle
the path when storing in GITHUB_ENV.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dfaec6dd-f5e5-43cb-b400-c42e6da6bb6b

📥 Commits

Reviewing files that changed from the base of the PR and between 4c7bdcf and 96709d7.

📒 Files selected for processing (10)
  • .github/workflows/build.yml
  • .github/workflows/ci.yml
  • .github/workflows/preview.yml
  • .github/workflows/release.yml
  • app/build.gradle.kts
  • build.gradle.kts
  • buildSrc/build.gradle.kts
  • buildSrc/src/main/kotlin/Helpers.kt
  • buildSrc/src/main/kotlin/RenameApkTask.kt
  • gradle/wrapper/gradle-wrapper.properties

Comment thread .github/workflows/release.yml Outdated
Comment thread buildSrc/src/main/kotlin/RenameApkTask.kt Outdated
Comment thread .github/workflows/build.yml Outdated
Comment thread buildSrc/src/main/kotlin/Helpers.kt Outdated
- RenameApkTask: drop builtArtifacts.save(outputDir). The metadata it
  writes references the original un-renamed APK paths (outputs/apk/...),
  not the NekoBox-* copies, so it would mislead any BuiltArtifactsLoader
  consumer (Greptile P1). Nothing downstream consumes it, so omit it.
- CI workflows (all four): pipe find through 'head -n 1' and quote
  dirname "$APK" to avoid multi-match / word-splitting corruption of
  GITHUB_ENV (CodeRabbit + Greptile P2).
- Helpers.kt: add trailing newline (Greptile P2).

Re-verified app:assembleOssDebug builds and renameApksForOssDebug emits
the four NekoBox-<ver>-<abi>.apk files.
@hawkff hawkff merged commit b23314d into main Jun 23, 2026
5 checks passed
@hawkff hawkff deleted the chore/agp9-migration branch June 23, 2026 02:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant